﻿#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stddef.h>

//*结构体对齐规则（计算结构体大小）：
//1.第一个成员在与结构体变量偏移量为0的地址处。
//2.其他成员变量要对齐到某个数字（对齐数)的整数倍的地址处。
	// 对齐数 = 编译器默认的一个对齐数与该成员大小的——较小值。(VS中默认的值为8)
//3.结构体总大小为——最大对齐数(每个成员变量都有一个对齐数)的整数倍。
//4.如果嵌套了结构体的情况，嵌套的结构体对齐到自己的最大对齐数的整数倍处，结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

//struct S
//{
//	char c1;
//	int i;
//	char c2;
//};
//
//struct S2
//{
//	char c1;
//	int i;
//	double d;//8
//};

//struct S3
//{
//	char c1;
//	char c2;
//	int i;
//};
//
//struct S4
//{
//	double d;
//	char c;
//	int i;
//};
//struct S5
//{
//	char c1;
//	struct S4 s4;
//	double d;
//};
//int main()
//{
//	struct S s = {0};
//	struct S2 s2 = { 0 };
//	struct S3 s3 = { 0 };
//	struct S4 s4 = { 0 };
//	struct S5 s5 = { 0 };
//	printf("%d\n", sizeof(s5));
//	printf("%d\n", sizeof(s));
//	printf("%d\n", sizeof(s2));
//	printf("%d\n", sizeof(s3));
//	printf("%d\n", sizeof(s4));
//	return 0;
//}

//修改默认对齐数
//默认对齐数是8
//把默认对齐数改为2

//#pragma pack(2)
//struct S
//{
//	char c1;//0
//	int i;//
//	char c2;//
//};
//#pragma pack()

//#pragma pack(1)
//struct S
//{
//	char c1;//1 1 1
//	int i;//4 1 1
//	char c2;//1 1 1
//};
//#pragma pack()
//
//int main()
//{
//	printf("%d\n", sizeof(struct S));//
//
//	return 0;
//}


//offsetof打印偏移量

//struct S
//{
//	char c1;
//	int i;
//	char c2;
//};
//
//int main()
//{
//	printf("%d\n", offsetof(struct S, c1));
//	printf("%d\n", offsetof(struct S, i));
//	printf("%d\n", offsetof(struct S, c2));
//
//	return 0;
//}

//结构体传参
//1.函数传参的时候，参数是需要压栈，会有时间和空间上的系统开销。
//2.如果传递一个结构体对象的时候，结构体过大，参数压栈的的系统开销比较大，
//所以会导致性能的下降。

//struct s 
//{
//	int data[1000];
//	int num;
//};
//struct s s = { {1,2,3,4 },1000};//结构体传参
//void print1(struct s s)
//{
//	printf("%d\n", s.num);
//}
////结构体地址传参
//void print2(struct s* ps)
//{
//	printf("%d\n", ps->num);
//}
//int main()
//{
//	print1(s); // 传结构体
//	print2(&s); //传地址
//	
//	return 0;
//}

//位段（节省空间）
//struct A 
//{
//	//先给4个字节 - 32bit
//	int _a : 2;		//_a成员占2个bit位
//	int _b : 5;		//_b成员占5个bit位
//	int _c : 10;	//_c成员占10个bit位
//	//此时省15个，不够30了，再开辟一个新的整型
//	//4个字节 - 32bit
//	int _d : 30;	//_d成员占30个bit位
//};
//
//int main()
//{
//	printf("%d \n", sizeof(struct A)); //8
//	return 0;
//}

//枚举
//enum color
//{
//	red = 2,
//	green,
//	blue
//};
//int main()
//{
//	enum color c = blue;
//	printf("%d\n", red);
//	printf("%d\n", green);
//	printf("%d\n", blue);
//
//	return 0;
//}

//枚举的优点：
/*1.增加代码的可读性和可维护性
  ⒉和#define定义的标识符比较枚举有类型检查，更加严谨
  3.防止了命名污染（封装)
  4.便于调试
  5.使用方便，一次可以定义多个常量
*/
//void menu()
//{
//	printf("*****************************\n");
//	printf("****  1. add    2. sub  *****\n");
//	printf("****  3. mul    4. div  *****\n");
//	printf("****  0. exit          *****\n");
//	printf("*****************************\n");
//}
//
//enum Option
//{
//	EXIT,//0
//	ADD,//1
//	SUB,//2
//	MUL,//3
//	DIV//4
//};
//
//int main()
//{
//	int input = 0;
//	do
//	{
//		menu();
//		printf("请选择:>");
//		scanf("%d", &input);
//		switch (input)
//		{
//		case ADD:
//			break;
//		case SUB:
//			break;
//		case MUL:
//			break;
//		case DIV:
//			break;
//		case EXIT:
//			break;
//		default:
//			break;
//		}
//	} while (input);
//
//
//	return 0;
//}

//联合体——共用体（即共用起始位置）
//union Un
//{
//	char c;
//	int i;
//};
//
//int main()
//{
//	union Un u;
//	printf("%p\n", &u);
//	printf("%p\n", &(u.c));
//	printf("%p\n", &(u.i));
//
//	return 0;
//}
//用联合体判断大小端存储类型(改一个，就全改)
//int check_sys()
//{
//	union U
//	{
//		char c;
//		int i;
//	}u;
//	u.i = 1;
//	return u.c;//0大端，1小端
//}
//int main()
//{
//	int ret = check_sys();
//	if (ret == 0)
//	{
//		printf("大端\n");
//	}
//	else
//	{
//		printf("小端\n");
//	}
//
//	return 0;
//}
// 
//联合体大小的判断
/*联合的大小至少是最大成员的大小。
当最大成员大小不是最大对齐数的整数倍的时候，就要对齐到最大对齐数的整数倍。*/
//union Un1 
//{
//	char c[5];
//	int i;
//};
//union Un2 
//{
//	short c[7];
//	int i;
//};
////下面输出的结果是什么?
//int main()
//{
//	printf("%d\n", sizeof(union Un1));
//	printf("%d\n", sizeof(union Un2));
//
//	return 0;
//}